{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Interact+InspectDR: Bode Plot Example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using InspectDR\n",
    "\n",
    "#When MIME\"image/svg+xml\" is disabled, Jupyter eventually requests PNG inline graphics:\n",
    "#(SVG outputs do not render well in notebooks for some reason...)\n",
    "InspectDR.defaults.rendersvg = false\n",
    "\n",
    "include(\"BodePlots.jl\") #Defines BodePlots.* utilities.\n",
    "\n",
    "nothing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Setup: Interact, Reactive, and Signals\n",
    "(Also create initial plot object)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using Interact, Reactive\n",
    "\n",
    "fopt = [(\"kHz\" => 1.0e3), (\"MHz\" => 1.0e6), (\"GHz\" => 1.0e9)] #Make sure to use Float64\n",
    "freqmap = Dict{Float64, String}(v=>s for (s,v) in fopt)\n",
    "fmult = Signal(Float64, 1e9) #Frequency multiplier\n",
    "annot = Signal(Bool, true) #Annotate plot\n",
    "fmax = Signal(Float64, 10) #Maximum plot frequency\n",
    "G = Signal(Float64, 20) #Gain (dB)\n",
    "fz = Signal(Float64, value(fmax)) #Zero frequency\n",
    "fp1 = Signal(Float64, .05) #Pole 1 frequency\n",
    "fp2 = Signal(Float64, .9) #Pole 2 frequency\n",
    "pobj = BodePlots.new() #Create initial plot object\n",
    "\n",
    "getfreqrange(fmax) = 1e-3:1e-3:fmax\n",
    "function update_range(widget, fmax)\n",
    "    widget.range = getfreqrange(fmax)\n",
    "    update_view(widget)\n",
    "end\n",
    "function frequency_slider(sig::Signal, fmax::Signal; label::String=\"\")\n",
    "    sld = slider(getfreqrange(value(fmax)), value=value(sig), label=label, signal=sig)\n",
    "    display(sld) #Must desplay before building updater, for some reason.\n",
    "    updater = map(_fmax->update_range(sld, _fmax), fmax)\n",
    "    return (sld, updater)\n",
    "end\n",
    "\n",
    "nothing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Interact/Reactive Control: Inline Plots\n",
    "Use sliders/text boxes to change pole frequency\n",
    "\n",
    "## TODO\n",
    "\n",
    " - Find good way to support log-spaced ranges for frequencies.\n",
    " - Find out why txt_fmax will not display when specifying `signal=`.\n",
    " - Find out why chk_annot hangs on 2nd execution of code block when specifying `signal=`.\n",
    " - Find out why one cannot display all widgets in a single statement (must display in stages for some reason).\n",
    " - Improve widgets layout (`hstack`?) once supported by Interact."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "tgl_fmult = togglebuttons(fopt, value_label=freqmap[value(fmult)], signal=fmult)\n",
    "#chk_annot = checkbox(value(annot), label=\"Display annotation\", signal=annot) #Hangs on 2nd execution of block\n",
    "chk_annot = checkbox(value(annot), label=\"Display annotation\")\n",
    "annot = signal(chk_annot) #Hack to avoid hangups\n",
    "map(display, [tgl_fmult, chk_annot])\n",
    "\n",
    "#txt_fmax = textbox(value(fmax), label=\"max freq\", signal=fmax) #Will not display - notebook hangs??\n",
    "txt_fmax = textbox(value(fmax), label=\"max freq\") #This one does not cause hangups\n",
    "fmax = signal(txt_fmax) #Hack to get fmax/txt_fmax working\n",
    "display(txt_fmax) #Will hang session using 1st method, for some reason\n",
    "\n",
    "#Gain slider:\n",
    "sld_G = slider(-10:1.0:100, value=value(G), label=\"Gain (dB)\", signal=G)\n",
    "display(sld_G)\n",
    "\n",
    "#Pole/zero sliders:\n",
    "(sld_fz, updater_fz) = frequency_slider(fz, fmax, label=\"zero\")\n",
    "(sld_fp1, updater_fp1) = frequency_slider(fp1, fmax, label=\"pole 1\")\n",
    "(sld_fp2, updater_fp2) = frequency_slider(fp2, fmax, label=\"pole 2\")\n",
    "#map(display, [sld_fz, sld_fp1, sld_fp2]) #Display now in frequency_slider()\n",
    "\n",
    "#Build widget list to control plot for future code blocks\n",
    "#TODO: Why do widgets have to be displayed in stages?\n",
    "widgetlist = [tgl_fmult, chk_annot, txt_fmax, sld_G, sld_fz, sld_fp1, sld_fp2]\n",
    "\n",
    "#Widget-controlled plot:\n",
    "updater_plot = map(fmult, fmax, G, fz, fp1, fp2, annot) do s, _fmax, _G, _fz, _fp1, _fp2, a\n",
    "    BodePlots.update(pobj, s*1e-3, _fmax*s, _G, _fz*s, _fp1*s, _fp2*s, a)\n",
    "end\n",
    "display(updater_plot)\n",
    "\n",
    "nothing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Interact/Reactive Control: Inspect/Gtk GUI\n",
    "(Re-display GUI controls for convenience)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gtkgui = display(InspectDR.GtkDisplay(), pobj) #Display plot in Gtk GUI.\n",
    "\n",
    "#Refresh GUI when plot changes:\n",
    "updater_gtkgui = map((p)->InspectDR.refresh(gtkgui), updater_plot)\n",
    "\n",
    "#Re-display GUI controls, for convenience:\n",
    "map(display, widgetlist)\n",
    "\n",
    "nothing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Demo complete!"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Julia 0.6.0",
   "language": "julia",
   "name": "julia-0.6"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "0.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
